package com.smart.system.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.smart.common.constant.GlobalConstants;
import com.smart.common.constant.UserConstants;
import com.smart.common.core.domain.entity.SysDept;
import com.smart.common.exception.ServiceException;
import com.smart.common.utils.DateUtils;
import com.smart.common.utils.SecurityUtils;
import com.smart.common.utils.StringUtils;
import com.smart.system.domain.*;
import com.smart.system.domain.dto.DeviceSettingsDto;
import com.smart.system.domain.vo.EmployeeScreenVo;
import com.smart.system.domain.vo.EmployeeSetVo;
import com.smart.system.domain.vo.EmployeeTrajectoryVo;
import com.smart.system.domain.vo.NowEmployeeTrajectoryVo;
import com.smart.system.mapper.EmployeeTrajectoryMapper;
import com.smart.system.service.*;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smart.system.mapper.EmployeeMapper;
import org.springframework.transaction.annotation.Transactional;

/**
 * 员工Service业务层处理
 *
 * @author smart
 * @date 2024-09-11
 */
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {

    @Lazy
    @Autowired
    private IEmployeeTrajectoryService employeeTrajectoryService;
    @Autowired
    private ISysPostService sysPostService;

    @Autowired
    private IAttendanceRecordService attendanceRecordService;

    @Autowired
    private ISysDeptService deptService;

    @Autowired
    private IAreaEmployeeService areaEmployeeService;

    @Autowired
    private IWatchesService watcherService;

    /**
     * 查询员工
     *
     * @param id 员工主键
     * @return 员工
     */
    @Override
    public Employee selectEmployeeById(String id) {
        Employee employee = this.baseMapper.selectById(id);

        if (employee!=null&&employee.getPosition() != null) {
            SysPost sysPost = sysPostService.selectPostById(employee.getPosition().longValue());
            //未选择岗位
            if (sysPost == null) {
                return employee;
            }
            employee.setPositionName(sysPost.getPostName());
        }
        return employee;
    }

    /**
     * 查询员工列表
     *
     * @param employee 员工
     * @return 员工
     */
    @Override
    public List<Employee> selectEmployeeList(Employee employee) {
        //获取当前部门及子部门
        List<SysDept> sysDepts = deptService.listDeptChildById(SecurityUtils.getDeptId());
        List<Long> deptIds = sysDepts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
        List<Employee> list = this.list(Wrappers.lambdaQuery(Employee.class)
                        .in(Employee::getDeptId, deptIds)
                .like(StringUtils.isNotEmpty(employee.getName()), Employee::getName, employee.getName())
                .like(StringUtils.isNotEmpty(employee.getPhone()), Employee::getPhone, employee.getPhone())
                .like(StringUtils.isNotEmpty(employee.getUserNumber()), Employee::getUserNumber, employee.getUserNumber())
        );
        List<SysPost> sysPosts = sysPostService.selectPostAll();
        for (Employee employee1 : list) {
            for (SysPost sysPost : sysPosts) {
                if (employee1.getPosition() != null && sysPost.getPostId().intValue() == employee1.getPosition()) {
                    employee1.setPositionName(sysPost.getPostName());
                }
            }
        }
        return list;
    }

    /**
     * 新增员工
     *
     * @param employee 员工
     * @return 结果
     */
    @Override
    public int insertEmployee(Employee employee) {
        //判断工号是否重复
        Employee count = this.baseMapper.selectOne(Wrappers.lambdaQuery(Employee.class).eq(Employee::getUserNumber, employee.getUserNumber()));
        if (count != null) {
            throw new ServiceException("工号已存在!");
        }
        employee.setCreateTime(DateUtils.getNowDate());
        return this.baseMapper.insert(employee);
    }

    /**
     * 修改员工
     *
     * @param employee 员工
     * @return 结果
     */
    @Override
    public int updateEmployee(Employee employee) {
        //不能修改成别人的工号
        Employee count = this.baseMapper.selectOne(Wrappers.lambdaQuery(Employee.class)
                .eq(Employee::getUserNumber, employee.getUserNumber())
                .ne(Employee::getId, employee.getId()));
        if (count != null) {
            throw new ServiceException("工号已存在!");
        }
        count = this.baseMapper.selectOne(Wrappers.lambdaQuery(Employee.class)
                .eq(Employee::getImei, employee.getImei())
                .ne(Employee::getId, employee.getId()));
        if(count != null){
            throw new ServiceException("IMEI号已存在!");
        }
        employee.setUpdateTime(DateUtils.getNowDate());
        return this.baseMapper.updateById(employee);
    }

    /**
     * 批量删除员工
     *
     * @param ids 需要删除的员工主键
     * @return 结果
     */
    @Override
    public int deleteEmployeeByIds(String[] ids) {
        return this.baseMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除员工信息
     *
     * @param id 员工主键
     * @return 结果
     */
    @Override
    public int deleteEmployeeById(String id) {
        return this.baseMapper.deleteById(id);
    }

    @Override
    public boolean frostEmployee(String id) {
        Employee employee = this.selectEmployeeById(id);
        if (employee != null) {
            employee.setStatus(UserConstants.NORMAL.equals(employee.getStatus()) ? UserConstants.USER_DISABLE : UserConstants.NORMAL);
        }
        this.updateById(employee);
        return true;
    }

    @Override
    public Employee getByImei(String imei) {
        return this.getOne(Wrappers.lambdaQuery(Employee.class).eq(Employee::getImei, imei));
    }

    @Override
    public IPage<EmployeeTrajectoryVo> listEmployeeTrajectory(String content, String startTime, String endTime, Page page) {
        Page<Employee> res = this.page(page, Wrappers.lambdaQuery(Employee.class)
                .like(content != null, Employee::getName, content).or(content != null, o -> o.like(Employee::getUserNumber, content))
        );
        if (res == null) return page;
        List<EmployeeTrajectory> list = Collections.emptyList();
        if (res.getRecords().size() > 0) {
            //如果开始时间-结束时间为空,则按照上班时间跟下班时间来算
            if(startTime == null||endTime == null){
                //获取用户上班时间
                startTime = DateUtils.getDate();
            }
            list = employeeTrajectoryService.list(Wrappers.lambdaQuery(EmployeeTrajectory.class)
                    .ge(startTime != null, EmployeeTrajectory::getCreateTime, startTime)
                    .le(endTime != null, EmployeeTrajectory::getCreateTime, endTime)
                    .orderByAsc(EmployeeTrajectory::getCreateTime)
            );
        }
        Page<EmployeeTrajectoryVo> resultPage = new Page<>();
        BeanUtils.copyProperties(res, resultPage);
        List<Employee> temp = new LinkedList<>(res.getRecords());
        resultPage.getRecords().clear();
        for (Employee employee : temp) {
            EmployeeTrajectoryVo vo = new EmployeeTrajectoryVo();
            BeanUtils.copyProperties(employee, vo);
            Integer id = vo.getId();
            AttendanceRecord attendanceRecord = attendanceRecordService.getOne(Wrappers.lambdaQuery(AttendanceRecord.class)
                    .eq(AttendanceRecord::getUserId, id)
                    .orderByDesc(AttendanceRecord::getAttendanceDate).last("limit 1"),false);
            vo.setAttendanceRecord(attendanceRecord);
            List<EmployeeTrajectory> trajectory = vo.getTrajectory();
            if (trajectory == null) {
                trajectory = new LinkedList<>();
            }
            int i = 0;
            for (EmployeeTrajectory employeeTrajectory : list) {
                if (vo.getId().equals(employeeTrajectory.getUserId())) {
                    employeeTrajectory.setSort(i++);
                    trajectory.add(employeeTrajectory);
                }
            }
            vo.setTrajectory(trajectory);
            resultPage.getRecords().add(vo);
        }
        return resultPage;
    }

    @Override
    public List<NowEmployeeTrajectoryVo> listTrajectoryToEmployee(Date startTime, Date endTime,Integer id) {
        //获取当前部门列表
        List<SysDept> depts = deptService.listDeptChildById(SecurityUtils.getDeptId());
        if (depts != null && depts.size() > 0) {
            List<NowEmployeeTrajectoryVo> result = new LinkedList<>();
            List<Long> deptIds = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
            List<Employee> employees = this.list(Wrappers.lambdaQuery(Employee.class).eq(id!=null,Employee::getId, id).in(Employee::getDeptId, deptIds));
            for (Employee employee : employees) {
                NowEmployeeTrajectoryVo nowEmployeeTrajectoryVo = new NowEmployeeTrajectoryVo();
                BeanUtils.copyProperties(employee,nowEmployeeTrajectoryVo);
                //查询人员今天最后上传地址
                EmployeeTrajectory trajectory = employeeTrajectoryService.getOne(Wrappers.lambdaQuery(EmployeeTrajectory.class)
                        .eq(EmployeeTrajectory::getUserId, employee.getId())
                        .ge(EmployeeTrajectory::getCreateTime, DateUtils.getDate())
                        .orderByDesc(EmployeeTrajectory::getCreateTime).last("limit 1"),false);
                nowEmployeeTrajectoryVo.setTrajectory(trajectory);
                //获取人员绑定的区域
                AreaEmployee areaEmployee = areaEmployeeService.getOne(Wrappers.lambdaQuery(AreaEmployee.class)
                        .eq(AreaEmployee::getEmployeeId, employee.getId()).last("limit 1"),false);
                if(areaEmployee!=null){
                    nowEmployeeTrajectoryVo.setAreaId(areaEmployee.getAreaId());
                }
                //查询人员今日移动轨迹
                List<EmployeeTrajectory> employeeTrajectories = employeeTrajectoryService.list(Wrappers.lambdaQuery(EmployeeTrajectory.class)
                        .eq(EmployeeTrajectory::getUserId, employee.getId())
                        .ge(startTime!=null,EmployeeTrajectory::getCreateTime,startTime)
                        .le(endTime!=null,EmployeeTrajectory::getCreateTime,endTime)
                        .orderByDesc(EmployeeTrajectory::getCreateTime)
                        .last(startTime==null||endTime==null,"limit 6"));
                //轨迹抽稀
                List<EmployeeTrajectory> locations = EnhancedTrajectorySimplifier.simplifyTrajectories(employeeTrajectories, 10, true);

                nowEmployeeTrajectoryVo.setEmployeeTrajectories(locations);
                //获取用户当前上班状态
                AttendanceRecord attendanceRecord = attendanceRecordService.getOne(Wrappers.lambdaQuery(AttendanceRecord.class)
                        .eq(AttendanceRecord::getUserId, employee.getId())
                        .ge(AttendanceRecord::getAttendanceDate, DateUtils.getDate()).last("limit 1"),false);
                if(attendanceRecord!=null){
                    nowEmployeeTrajectoryVo.setAttendanceRecord(attendanceRecord.getAttendance());
                }
                result.add(nowEmployeeTrajectoryVo);
            }
            return result;
        }
        return Collections.emptyList();
    }

    @Override
    public IPage<EmployeeScreenVo> listEmployeeScreen(Integer areaId, Page toPage) {
        LambdaQueryWrapper<Employee> query = Wrappers.lambdaQuery(Employee.class);
        if(areaId!=null){
            List<AreaEmployee> list = areaEmployeeService.list(Wrappers.lambdaQuery(AreaEmployee.class).eq(AreaEmployee::getAreaId, areaId));
            if(list.size()==0){
                return new Page(toPage.getCurrent(),toPage.getSize());
            }
            query.in(Employee::getId,list.stream().map(AreaEmployee::getEmployeeId).collect(Collectors.toList()));
        }else{
            return new Page(toPage.getCurrent(),toPage.getSize());
        }
        Page page = this.page(toPage,query);
        List<Employee> empList = page.getRecords();
        IPage<EmployeeScreenVo> resPage = new Page<>();
        BeanUtils.copyProperties(page,resPage,"records");
        ArrayList<EmployeeScreenVo> resList = new ArrayList<>();

        for (Employee record : empList) {
            EmployeeScreenVo vo = new EmployeeScreenVo();
            vo.setId(record.getId());
            vo.setName(record.getName());
            vo.setPhone(record.getPhone());
            //获取人员考勤状态
            AttendanceRecord attendanceRecord = attendanceRecordService.getOne(Wrappers.lambdaQuery(AttendanceRecord.class)
                    .eq(AttendanceRecord::getUserId, record.getId())
                    .ge(AttendanceRecord::getAttendanceDate, DateUtils.getDate()).last("limit 1"),false);
            if(attendanceRecord!=null){
                vo.setStatus(attendanceRecord.getAttendance());
            }else{
                vo.setStatus(GlobalConstants.ATTENDANCE_EXCEPTION);
            }
            resList.add(vo);
        }
        resPage.setRecords(resList);
        return resPage;
    }

    @Override
    public AreaLocation getLocation(Integer id) {
        EmployeeTrajectory one = employeeTrajectoryService.getOne(Wrappers.lambdaQuery(EmployeeTrajectory.class)
                .eq(EmployeeTrajectory::getUserId, id)
                .orderByDesc(EmployeeTrajectory::getCreateTime)
                .last("limit 1"),false);
        if(one==null){
            return null;
        }else{
            return one.getAreaLocation();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean setWatches(EmployeeSetVo employeeSetVo) {
        boolean flag = false;
        for (String imei : employeeSetVo.getImeis()) {
            DeviceSettingsDto deviceSettingsDto = new DeviceSettingsDto();
            BeanUtils.copyProperties(employeeSetVo,deviceSettingsDto);
            deviceSettingsDto.setDeviceid(imei);
            flag = watcherService.setDevice(deviceSettingsDto);
        }
        if(flag){
            this.update(Wrappers.lambdaUpdate(Employee.class)
                    .in(Employee::getImei, employeeSetVo.getImeis())
                    .set(Employee::getLocationTimeInterval,employeeSetVo.getLocationtimeinterval())
                    .set(Employee::getHeartRateTimeInterval,employeeSetVo.getHeartratetimeinterval())
                    .set(Employee::getBpi,employeeSetVo.getBpi())
                    .set(Employee::getTpi,employeeSetVo.getTpi())
                    .set(Employee::getOxi,employeeSetVo.getOxi())
                    .set(Employee::getSos1,employeeSetVo.getSos1())
                    .set(Employee::getSos2,employeeSetVo.getSos2())
                    .set(Employee::getSos3,employeeSetVo.getSos3())
                    .set(Employee::getMaxHeartRate,employeeSetVo.getMaxheartrate())
                    .set(Employee::getMinHeartRate,employeeSetVo.getMinheartrate())
                    .set(Employee::getBpHighMax,employeeSetVo.getBphighmax())
                    .set(Employee::getBpHighMin,employeeSetVo.getBphighmin())
                    .set(Employee::getBpLowMax,employeeSetVo.getBplowmax())
                    .set(Employee::getBpLowMin,employeeSetVo.getBplowmin())
                    .set(Employee::getBloodOxMax,employeeSetVo.getBloodoxmax())
                    .set(Employee::getBloodOxMin,employeeSetVo.getBloodoxmin())
                    .set(Employee::getTempMax,employeeSetVo.getTempmax())
                    .set(Employee::getTempMin,employeeSetVo.getTempmin())
                    .set(Employee::getFallDown,employeeSetVo.getFalldown())
                    .set(Employee::getCloseInter,employeeSetVo.getCloseInter()));
            return true;
        }
        return false;
    }

    @Override
    public IPage<Employee> selectEmployeePage(Employee employee, IPage pageParam) {
        //获取当前部门及子部门
        List<SysDept> sysDepts = deptService.listDeptChildById(SecurityUtils.getDeptId());
        List<Long> deptIds = sysDepts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
        IPage<Employee> page = this.page(pageParam,Wrappers.lambdaQuery(Employee.class)
                .in(Employee::getDeptId, deptIds)
                .like(StringUtils.isNotEmpty(employee.getName()), Employee::getName, employee.getName())
                .like(StringUtils.isNotEmpty(employee.getPhone()), Employee::getPhone, employee.getPhone())
                .like(StringUtils.isNotEmpty(employee.getUserNumber()), Employee::getUserNumber, employee.getUserNumber())
        );
        List<SysPost> sysPosts = sysPostService.selectPostAll();
        for (Employee employee1 : page.getRecords()) {
            for (SysPost sysPost : sysPosts) {
                if (employee1.getPosition() != null && sysPost.getPostId().intValue() == employee1.getPosition()) {
                    employee1.setPositionName(sysPost.getPostName());
                }
            }
        }
        return page;
    }
}
